﻿//CandleSerializer.cs
//Copyright (c) 2013 StockSharp LLC, all rights reserved.
//This code module is part of StockSharp library.
//This code is licensed under the GNU GENERAL PUBLIC LICENSE Version 3.
//See the file License.txt for the license details.
//More info on: http://stocksharp.com

namespace StockSharp.Algo.Storages
{
	using System;
	using System.Collections.Generic;
	using System.IO;
	using System.Linq;

	using Ecng.Common;
	using Ecng.Serialization;

	using StockSharp.Algo.Candles;
	using StockSharp.BusinessEntities;

	class CandleMetaInfo : MetaInfo<CandleMetaInfo>
	{
		public CandleMetaInfo(DateTime date)
			: base(date)
		{
		}

		public override void Write(Stream s)
		{
			base.Write(s);

			s.Write(FirstPrice);
			s.Write(LastPrice);
		}

		public override void Read(Stream s)
		{
			base.Read(s);

			FirstPrice = s.Read<decimal>();
			LastPrice = s.Read<decimal>();
		}

		protected override void CopyFrom(CandleMetaInfo src)
		{
			base.CopyFrom(src);

			FirstPrice = src.FirstPrice;
			LastPrice = src.LastPrice;
		}
	}

	class CandleSerializer<TCandle> : MarketDataSerializer<TCandle, CandleMetaInfo>
		where TCandle : Candle, new()
	{
		private readonly object _arg;

		public CandleSerializer(Security security, object arg)
			: base(security, 74)
		{
			if (arg == null)
				throw new ArgumentNullException("arg");

			_arg = arg;
		}

		protected override void OnSave(List<bool> bits, IEnumerable<TCandle> candles, CandleMetaInfo metaInfo)
		{
			if (metaInfo.IsEmpty())
			{
				var firstCandle = candles.First();

				metaInfo.FirstPrice = firstCandle.LowPrice;
				metaInfo.LastPrice = firstCandle.LowPrice;
			}

			bits.SerializeInt(candles.Count());

			foreach (var candle in candles)
			{
				var arg = candle.Arg;

				if (!arg.Equals(_arg))
					throw new ArgumentException("Неправильный параметр свечки {0}. Параметр свечки равен {1}, хранилище принимает {2}.".Put(candle, candle.Arg, _arg), "candles");
				
				bits.SerializeVolume(candle.TotalVolume);
				bits.SerializeVolume(candle.RelativeVolume);

				bits.SerializePrice(candle.LowPrice, metaInfo.LastPrice, metaInfo.MinStepSize, Security);
				metaInfo.LastPrice = candle.LowPrice;

				bits.SerializePrice(candle.OpenPrice, metaInfo.LastPrice, metaInfo.MinStepSize, Security);
				bits.SerializePrice(candle.ClosePrice, metaInfo.LastPrice, metaInfo.MinStepSize, Security);
				bits.SerializePrice(candle.HighPrice, metaInfo.LastPrice, metaInfo.MinStepSize, Security);

				metaInfo.LastTime = bits.SerializeTime(candle.OpenTime, metaInfo.LastTime, "свечки (время открытия)");
				var time = bits.SerializeTime(candle.CloseTime, metaInfo.LastTime, "свечки (время закрытия)");
				if (metaInfo.Version >= MarketDataVersions.Version41)
					metaInfo.LastTime = time;

				bits.SerializeInt((int)candle.State);
			}
		}

		public override TCandle MoveNext(MarketDataEnumerator<TCandle, CandleMetaInfo> enumerator)
		{
			var reader = enumerator.Reader;
			var metaInfo = enumerator.MetaInfo;

			var candle = new TCandle
			{
				Security = Security,
				Arg = _arg,
				TotalVolume = reader.DeserializeVolume(),
				RelativeVolume = reader.DeserializeVolume(),
				LowPrice = reader.DeserializePrice(metaInfo.FirstPrice, metaInfo.MinStepSize)
			};

			candle.OpenPrice = reader.DeserializePrice(candle.LowPrice, metaInfo.MinStepSize);
			candle.ClosePrice = reader.DeserializePrice(candle.LowPrice, metaInfo.MinStepSize);
			candle.HighPrice = reader.DeserializePrice(candle.LowPrice, metaInfo.MinStepSize);

			candle.OpenTime = reader.DeserializeTime(enumerator.Date, metaInfo.FirstTime);
			candle.CloseTime = reader.DeserializeTime(enumerator.Date, candle.OpenTime);

			candle.State = (CandleStates)reader.DeserializeInt();

			metaInfo.FirstPrice = candle.LowPrice;
			metaInfo.FirstTime = metaInfo.Version <= MarketDataVersions.Version40 ? candle.OpenTime : candle.CloseTime;

			return candle;
		}
	}
}